﻿using IceCS.Puke.Core;
using IceCS.Puke.Core.PukeEventHandler;
using System;
using System.Collections.Generic;

namespace IceCS.Puke.Client
{
    /// <summary>
    /// 游戏主体逻辑
    /// </summary>
    public class Game
    {
        #region 私有属性
        /// <summary>
        /// 要使用的一个牌堆
        /// </summary>
        private readonly Deck _playDeck;
        /// <summary>
        /// 当前的卡牌
        /// </summary>
        private int _currentCard;
        /// <summary>
        /// 玩家列表
        /// </summary>
        private List<Player> _playerList;
        /// <summary>
        /// 使用过的牌
        /// </summary>
        private readonly CardList _discardedCardList;
        /// <summary>
        /// 临时卡牌，用于临时存储翻开的牌和丢弃进废弃牌堆的牌
        /// </summary>
        private Card _tempCard;
        /// <summary>
        /// 表示是否有玩家胜利
        /// </summary>
        private bool _gameWin;

        #endregion

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public Game()
        {
            _currentCard = 1;
            _discardedCardList = new CardList();
            _playDeck = new Deck(isAceHigh: true);
            _playDeck.Shuffle();
            _gameWin = false;
            _playDeck.LastCardDrawn += PlayDeck_LastCardDrawn;
        }


        #region 私有方法
        /// <summary>
        /// 给每个玩家发7张手牌
        /// </summary>
        private void DealHands()
        {
            _playerList.ForEach(p =>
            {
                int i = 7;
                while (i != 0)
                {
                    p.PlayHand.Add(_playDeck.GetCard(_currentCard));
                    i -= 1;
                    _currentCard += 1;
                }
            });
        }

        /// <summary>
        /// 执行每个玩家的逻辑
        /// </summary>
        /// <param name="player">玩家对象</param>
        /// <returns></returns>
        private Player DoEveryPlayerLogic(Player player)
        {
            // 展示牌
            Console.WriteLine("------------------------------------------");
            Console.WriteLine($"轮到玩家 【{player.Name}】");
            Console.WriteLine("---------------");
            Console.WriteLine("当前手牌：");
            PrintPlayerHandCard(player);
            Console.WriteLine("现在桌面上翻开的牌：【{0}】", _tempCard.ToChineseString());

            //拿牌
            var input = GameHelper.GetRightInput("按 T(take) 键把桌面上的牌放进手牌 按 D(discard) 键舍弃桌面上的然后拿一张新牌", new[] { "t", "T", "d", "D" });

            //直接拿桌面上的牌
            if (input.ToLower().Equals("t"))
            {
                Console.WriteLine("把 【{0}】 放入手牌", _tempCard.ToChineseString());
                //牌堆拿到最后一张牌后，会进行洗牌，然后重新拿牌，就要考虑牌是否在舍弃的牌堆里面
                //如果在的话，则从废弃牌堆拿出来
                if (_discardedCardList.Contains(_tempCard))
                {
                    _discardedCardList.Remove(_tempCard);
                }

                player.PlayHand.Add(_tempCard);
            }

            //舍弃桌面上的牌，拿一张新牌
            if (input.ToLower().Equals("d"))
            {
                //判断卡牌是否可用,只要不是玩家的手牌里面的和废弃牌堆里面的，就是可用的牌
                bool cardIsAvailable = false;
                //新的卡牌
                Card newCard = null;
                while (!cardIsAvailable)
                {
                    newCard = _playDeck.GetCard(_currentCard);
                    _currentCard += 1;
                    //确认废弃牌堆不包含
                    bool isContain = _discardedCardList.Contains(newCard);
                    //
                    foreach (var p in _playerList)
                    {
                        if (p.PlayHand.Contains(newCard))
                        {
                            isContain = true;
                            break;
                        }
                    }
                    if (!isContain)
                    {
                        cardIsAvailable = true;
                    }
                }
                Console.WriteLine($"新牌为【{newCard.ToChineseString()}】 ，放入手牌");
                player.PlayHand.Add(newCard);
            }

            //舍弃手牌中的一张，舍弃的牌作为在桌面上展示的牌
            Console.WriteLine("现在的手牌：");
            var condition = PrintPlayerHandCard(player);
            input = GameHelper.GetRightInput("选择要扔掉的手牌牌(输入编号)：", condition);

            var choice = int.Parse(input);
            _tempCard = player.PlayHand[choice - 1];
            player.PlayHand.RemoveAt(choice - 1);
            _discardedCardList.Add(_tempCard);
            Console.WriteLine($"丢弃的牌：【{_tempCard.ToChineseString()}】\r\n");

            _gameWin = player.HasWin();
            if (_gameWin)
            {
                return player;
            }
            return null;
        }
        /// <summary>
        /// 输出玩家的手牌
        /// </summary>
        /// <param name="player"></param>
        private string[] PrintPlayerHandCard(Player player)
        {
            player.PlayHand.Sort(Card.Comparer.Default);
            var i = 1;
            string[] ids = new string[player.PlayHand.Count];
            player.PlayHand.ForEach(c =>
            {
                ids[i - 1] = i.ToString();
                Console.WriteLine($"{i} : {c.ToChineseString()}");
                i += 1;
            });
            return ids;
        }
        #endregion

        #region 公共方法
        /// <summary>
        /// 设置玩家列表，数量范围只能在2和7之间(包括2和7)
        /// </summary>
        /// <param name="playerList"></param>
        public void SetPlayerList(List<Player> playerList)
        {
            if (playerList.Count > 7 || playerList.Count < 2)
            {
                throw new ArgumentOutOfRangeException(nameof(playerList), "玩家列表的数量范围只能在2和7之间(包括2和7)");
            }
            _playerList = playerList;
        }

        /// <summary>
        /// 进行游戏主循环,调用此方法前先调用 <see cref="SetPlayerList"/> 方法
        /// </summary>
        /// <returns></returns>
        /// <exception cref="ArgumentException" ></exception>
        public Player PlayGame()
        {
            if (_playerList == null)
            {
                throw new ArgumentException("请调用 SetPlayerList() 方法设置玩家");
            }

            DealHands();

            //开局翻开一张牌
            _tempCard = _playDeck.GetCard(_currentCard);
            _currentCard += 1;
            _discardedCardList.Add(_tempCard);

            int round = 1;
            Player winner = null;
            while (!_gameWin)
            {
                Console.WriteLine("----------------- 第 {0} 局 -----------------", round);
                foreach (var p in _playerList)
                {
                    winner = DoEveryPlayerLogic(p);
                    if (_gameWin)
                    {
                        break;
                    }
                }
                round += 1;
            }
            return winner;
        }

        #endregion

        #region Events
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlayDeck_LastCardDrawn(object sender, LastCardDrawnEventArgs e)
        {
            Console.WriteLine("牌已发完，重新洗牌，从废弃牌堆中选牌");
            (sender as Deck)?.Shuffle();
            //清空废弃牌堆
            _discardedCardList.Clear();
            _currentCard = 1;
        }

        #endregion
    }
}
